package imageEditor;

import gmmxEditor.GUI.CButton;
import gmmxEditor.GUI.ImageFilter;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class Main {

	private JFrame			frame;
	private JTextField		textField;
	private JTextField		textField_1;
	private JTextField		textField_2;
	private JTextField		textField_3;

	private JButton			btnSet;
	private JButton			btnGet;

	private JLabel			positionLbl;

	private DrawingPanel	panel;

	private BufferedImage	img;

	private int				zoomLevel	= 1;

	private int				pixelSize	= 1;

	private boolean			rem			= false;
	private boolean			add			= false;

	private Cursor			blankCursor;

	private Cursor			defaultCursor;

	private Color			color;

	private CButton			colorButton;

	private boolean			draw		= true;

	private String			fileName	= "";

	/**
	 * File chooser window
	 */
	final JFileChooser		fc			= new JFileChooser();

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					Main window = new Main();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public Main() {
		this.initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {

		this.frame = new JFrame();
		this.frame.setBounds(100, 100, 648, 442);
		this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.frame.setLocationRelativeTo(null);

		this.frame.getContentPane().setLayout(null);

		BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);

		this.blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor");

		this.defaultCursor = this.frame.getContentPane().getCursor();

		JMenuBar menuBar = new JMenuBar();
		this.frame.setJMenuBar(menuBar);

		JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);

		JMenuItem mntmOpen = new JMenuItem("Open");
		mntmOpen.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Main.this.fc.setAcceptAllFileFilterUsed(false);
				Main.this.fc.removeChoosableFileFilter(null);
				Main.this.fc.setFileFilter(new ImageFilter());
				int returnVal = Main.this.fc.showOpenDialog(Main.this.frame);

				if (returnVal == JFileChooser.APPROVE_OPTION) {
					File file = Main.this.fc.getSelectedFile();

					try {//check if the image is in OTX format
						Main.this.img = ImageIO.read(file);

						Main.this.fileName = Main.this.fc.getSelectedFile().getAbsolutePath();

						Main.this.panel.repaint();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
			}
		});
		mnFile.add(mntmOpen);

		this.panel = new DrawingPanel();

		KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
			@Override
			public boolean dispatchKeyEvent(KeyEvent e) {
				//System.out.println(e.getKeyCode());
				if (e.getKeyCode() != 93) {
					Main.this.add = false;
				}

				if (e.getKeyCode() != 47) {
					Main.this.rem = false;
				}

				if (e.isControlDown() && (e.getKeyCode() == 93) && !Main.this.add) {
					Main.this.add = true;
					Main.this.zoomLevel++;
					Main.this.panel.repaint();
				}
				if (e.isControlDown() && (e.getKeyCode() == 47) && !Main.this.rem) {
					Main.this.rem = true;
					Main.this.zoomLevel--;
					Main.this.panel.repaint();
				}
				return false;
			}
		});

		this.panel.addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseMoved(MouseEvent e) {//Mouse moved over map Panel
				if (Main.this.img == null) {
					return;
				}

				if (Main.this.panel.isPixelDisplaying()) {
					Main.this.frame.getContentPane().setCursor(Main.this.blankCursor);
				} else {
					Main.this.frame.getContentPane().setCursor(Main.this.defaultCursor);
				}

				int x = (int) e.getPoint().getX();
				int y = (int) e.getPoint().getY();

				Point p = new Point(x, y);

				if (!p.equals(Main.this.panel.getPointerPosition())) {
					Main.this.panel.setPointer(p);
					Main.this.panel.repaint();
				}
			}
		});

		this.panel.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseExited(MouseEvent e) {//moused moved away from map Panel
				Main.this.panel.setPointer(null);
				Main.this.frame.getContentPane().setCursor(Main.this.defaultCursor);
				Main.this.panel.repaint();
			}
		});

		this.panel.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (Main.this.draw) {
					Main.this.drawPixel((int) Main.this.panel.getPointerPosition().getX(), (int) Main.this.panel.getPointerPosition().getY(), Main.this.color);
					Main.this.panel.repaint();
				} else {
					Main.this.setColor(PngImage.getColor((int) Main.this.panel.getPointerPosition().getX(), (int) Main.this.panel.getPointerPosition().getY(),
							Main.this.img));// new Color(img.getRGB((int)panel.getPointerPosition().getX(), (int)panel.getPointerPosition().getY())));
				}
			}
		});

		this.panel.setBorder(null);
		this.panel.setBackground(Color.WHITE);
		this.panel.setLayout(null);

		JScrollPane scroller = new JScrollPane(this.panel);
		scroller.setBounds(6, 6, 512, 356);

		this.frame.getContentPane().add(scroller);

		JPanel panel_1 = new JPanel();
		panel_1.setBounds(518, 6, 123, 356);
		this.frame.getContentPane().add(panel_1);
		panel_1.setLayout(null);

		JLabel lblRed = new JLabel("Red:");
		lblRed.setBounds(6, 12, 48, 16);
		panel_1.add(lblRed);

		JLabel lblGreen = new JLabel("Green:");
		lblGreen.setBounds(6, 46, 48, 16);
		panel_1.add(lblGreen);

		JLabel lblBlue = new JLabel("Blue:");
		lblBlue.setBounds(6, 80, 48, 16);
		panel_1.add(lblBlue);

		JLabel lblAlpha = new JLabel("Alpha:");
		lblAlpha.setBounds(6, 114, 48, 16);
		panel_1.add(lblAlpha);

		this.textField = new JTextField();
		this.textField.setText("0");
		this.textField.setBounds(45, 6, 72, 28);
		panel_1.add(this.textField);
		this.textField.setColumns(10);

		this.textField.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void removeUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void insertUpdate(DocumentEvent e) {
				this.warn();
			}

			public void warn() {
				if (Main.this.textField.getText().length() > 0) {
					Main.this.updateColor();
				}
			}
		});

		this.textField_1 = new JTextField();
		this.textField_1.setText("0");
		this.textField_1.setColumns(10);
		this.textField_1.setBounds(45, 40, 72, 28);
		panel_1.add(this.textField_1);

		this.textField_1.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void removeUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void insertUpdate(DocumentEvent e) {
				this.warn();
			}

			public void warn() {
				if (Main.this.textField_1.getText().length() > 0) {
					Main.this.updateColor();
				}
			}
		});

		this.textField_2 = new JTextField();
		this.textField_2.setText("0");
		this.textField_2.setColumns(10);
		this.textField_2.setBounds(45, 74, 72, 28);
		panel_1.add(this.textField_2);

		this.textField_2.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void removeUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void insertUpdate(DocumentEvent e) {
				this.warn();
			}

			public void warn() {
				if (Main.this.textField_2.getText().length() > 0) {
					Main.this.updateColor();
				}
			}
		});

		this.textField_3 = new JTextField();
		this.textField_3.setText("0");
		this.textField_3.setColumns(10);
		this.textField_3.setBounds(45, 108, 72, 28);
		panel_1.add(this.textField_3);

		this.textField_3.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void removeUpdate(DocumentEvent e) {
				this.warn();
			}

			@Override
			public void insertUpdate(DocumentEvent e) {
				this.warn();
			}

			public void warn() {
				if (Main.this.textField_3.getText().length() > 0) {
					Main.this.updateColor();
				}
			}
		});

		this.colorButton = new CButton("");
		this.colorButton.setBounds(6, 142, 111, 29);
		panel_1.add(this.colorButton);

		this.btnSet = new JButton("S");
		this.btnSet.setEnabled(false);
		this.btnSet.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Main.this.draw = true;
				Main.this.btnSet.setEnabled(false);
				Main.this.btnGet.setEnabled(true);
			}
		});
		this.btnSet.setBounds(6, 180, 40, 28);
		panel_1.add(this.btnSet);

		this.btnGet = new JButton("G");
		this.btnGet.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Main.this.draw = false;
				Main.this.btnSet.setEnabled(true);
				Main.this.btnGet.setEnabled(false);
			}
		});
		this.btnGet.setBounds(77, 180, 40, 28);
		panel_1.add(this.btnGet);

		this.positionLbl = new JLabel("(0:0)");
		this.positionLbl.setHorizontalAlignment(SwingConstants.CENTER);
		this.positionLbl.setBounds(518, 376, 84, 16);
		this.frame.getContentPane().add(this.positionLbl);
	}

	private void updateColor() {
		this.color = new Color(Integer.parseInt(this.textField.getText()), Integer.parseInt(this.textField_1.getText()), Integer.parseInt(this.textField_2
				.getText()), Integer.parseInt(this.textField_3.getText()));
		this.colorButton.setBackground(this.color);
		this.colorButton.repaint();
	}

	private void setColor(Color c) {
		this.color = c;
		this.textField.setText(c.getRed() + "");
		this.textField_1.setText(c.getGreen() + "");
		this.textField_2.setText(c.getBlue() + "");
		this.textField_3.setText(c.getAlpha() + "");
	}

	public void drawPixel(int x, int y, Color c) {
		int col = (c.getAlpha() << 24) | (c.getRed() << 16) | (c.getGreen() << 8) | c.getBlue();
		this.img.setRGB(x, y, col);
		this.panel.repaint();

		//saving image
		File outputfile = new File(this.fileName);
		try {
			ImageIO.write(this.img, "png", outputfile);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Panel that will draw the image (pattern used for scrolling scope)
	 */
	public class DrawingPanel extends JPanel {

		private static final long	serialVersionUID	= 1L;

		private Point				position			= null;

		private int					pixelTrigger		= 5;

		/**
		 * Draws the map, if present, and all the lines over it
		 */
		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);

			if (Main.this.img != null) {
				Main.this.panel
						.setPreferredSize(new Dimension(Main.this.img.getWidth() * Main.this.zoomLevel, Main.this.img.getHeight() * Main.this.zoomLevel));

				Main.this.panel.revalidate();

				g.drawImage(Main.this.img, 0, 0, Main.this.img.getWidth() * Main.this.zoomLevel, Main.this.img.getHeight() * Main.this.zoomLevel, null);//map drawing

				g.setColor(new Color(0, 0, 0));//Color(255,255,255));//setting color

				Main.this.pixelSize = Main.this.zoomLevel;

				if (Main.this.pixelSize > this.pixelTrigger) {
					for (int i = 0; i < (Main.this.img.getHeight() * Main.this.zoomLevel); i += Main.this.pixelSize) {//horizontal drawing
						g.drawLine(0, i, Main.this.img.getWidth() * Main.this.zoomLevel, i);
					}

					for (int i = 0; i < (Main.this.img.getWidth() * Main.this.zoomLevel); i += Main.this.pixelSize) {//vertical drawing
						g.drawLine(i, 0, i, Main.this.img.getHeight() * Main.this.zoomLevel);
					}
				}

				if (this.position != null) {
					g.fillRect((int) (this.position.getX() * Main.this.pixelSize), (int) (this.position.getY() * Main.this.pixelSize), Main.this.pixelSize,
							Main.this.pixelSize);
					g.setColor(new Color(255, 255, 255));
					g.drawLine((int) (this.position.getX() * Main.this.pixelSize), (int) (this.position.getY() * Main.this.pixelSize),
							(int) (this.position.getX() * Main.this.pixelSize) + Main.this.pixelSize, (int) (this.position.getY() * Main.this.pixelSize)
									+ Main.this.pixelSize);
					g.drawLine((int) (this.position.getX() * Main.this.pixelSize) + Main.this.pixelSize, (int) (this.position.getY() * Main.this.pixelSize),
							(int) (this.position.getX() * Main.this.pixelSize), (int) (this.position.getY() * Main.this.pixelSize) + Main.this.pixelSize);
					//g.drawLine((int)(position.getX() * pixelSize + pixelSize / 2), (int)(position.getY() * pixelSize) + 2, (int)(position.getX() * pixelSize + pixelSize / 2), (int)(position.getY() * pixelSize + pixelSize) - 2);
					//g.drawLine((int)(position.getX() * pixelSize) + 2, (int)(position.getY() * pixelSize + pixelSize / 2), (int)(position.getX() * pixelSize + pixelSize) - 2, (int)(position.getY() * pixelSize + pixelSize / 2));
				}

			}
		}

		public void setPointer(Point position) {
			if (position == null) {
				this.position = null;
				Main.this.positionLbl.setText("(0:0)");
				return;
			}

			this.position = new Point((int) Math.floor(position.getX() / Main.this.zoomLevel), (int) Math.floor(position.getY() / Main.this.zoomLevel));

			Main.this.positionLbl.setText("(" + (int) (this.position.getX() + 1) + ":" + (int) (this.position.getY() + 1) + ")");
		}

		public Point getPointerPosition() {
			if (this.position != null) {
				return this.position;
			}
			return new Point(0, 0);
		}

		public boolean isPixelDisplaying() {
			return Main.this.zoomLevel >= this.pixelTrigger;
		}
	}
}
